package com.tebiecloud.mpopen.server.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.tebiecloud.common.utils.JsonUtils;
import com.tebiecloud.common.utils.RedisUtils;
import com.tebiecloud.common.utils.StringUtils;
import com.tebiecloud.mpopen.client.constants.MpopenConstants;
import com.tebiecloud.mpopen.server.properties.MpopenProperties;
import com.tebiecloud.mpopen.server.service.MpopenCallbackService;
import com.tebiecloud.mpopen.server.utils.MPSuiteApi;
import com.tebiecloud.mpopen.server.utils.aes.WXBizMsgCrypt;
import com.tebiecloud.mpweixin.client.constants.QueueConstants;
import com.tebiecloud.mpweixin.client.model.MpUserVisit;
import com.tebiecloud.mpweixin.client.model.mpweixin.MPReceiveEventInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * 第三方平台回调处理
 * @Author: tebie
 * @Date: 2019-09-07 16:33
 */
@Slf4j
@Service
public class MpopenCallbackServiceImpl implements MpopenCallbackService {

    @Autowired
    private MpopenProperties mpopenProperties;

    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private AmqpTemplate amqpTemplate;

    public static final String []MESSAGE_MPTYPE = {"text", "image", "voice"}; // 企业号客服只支持发文本，图片，文件，语音，所以只处理这几类公众号消息类型

    @Override
    public String event(String msgSignature, String timestamp, String nonce, String body) throws Exception {
        String mpsuite_appid = mpopenProperties.getAppid();
        JSONObject jsonObj = mpsuiteDecryp(mpsuite_appid, msgSignature, timestamp, nonce, body);
        if(jsonObj == null) {
            return null;
        }
        log.info("xiaoc>> 第三方平台回调事件，msg: {}", jsonObj.toString());

        // 根据消息类型分配处理任务
        String InfoType = jsonObj.getString("InfoType");

        if("component_verify_ticket".equalsIgnoreCase(InfoType)) { // 推送component_verify_ticket
            String mpsuite_appsecret = mpopenProperties.getAppsecret();
            String ComponentVerifyTicket = jsonObj.getString("ComponentVerifyTicket");

            String reqD = String.format("{\"component_appid\":\"%s\" , \"component_appsecret\": \"%s\", \"component_verify_ticket\": \"%s\"}", mpsuite_appid, mpsuite_appsecret, ComponentVerifyTicket);
            String respD = MPSuiteApi.api_component_token(reqD);
            JSONObject jsonO = JsonUtils.str2Json(respD);
            if(jsonO != null && !StringUtils.isEmpty(jsonO.getString("component_access_token"))) {
                String component_access_token = jsonO.getString("component_access_token");
                log.info("xiaoc>> 保存接口调用凭据，mpsuite_appid: {}, component_access_token: {}", mpsuite_appid, component_access_token);
                redisUtils.set(MpopenConstants.COMPONENT_ACCESS_TOKEN_ + mpsuite_appid, component_access_token);
            }
        } else if("authorized".equalsIgnoreCase(InfoType)) { // 授权成功的通知
            log.info("xiaoc>> 公众号授权成功通知，但不做处理");
        } else if("updateauthorized".equalsIgnoreCase(InfoType)) { // 更新授权的通知
            log.info("xiaoc>> 更新公众号授权通知，但不做处理");
        } else if("unauthorized".equalsIgnoreCase(InfoType)) { // 取消授权的通知
            log.info("xiaoc>> 公众号取消授权通知，但不做处理");
        } else {
            log.info("xiaoc>> 忽略的消息类型，InfoType: {}", InfoType);
        }

        return "success";
    }

    @Override
    public String msgReceive(String appid, String msgSignature, String timestamp, String nonce, String body) throws Exception {
        String mpsuite_appid = mpopenProperties.getAppid();
        JSONObject jsonObj = mpsuiteDecryp(mpsuite_appid, msgSignature, timestamp, nonce, body);
        if(jsonObj == null) {
            return null;
        }
        log.info("xiaoc>> 第三方平台回调消息，msg: {}", jsonObj.toString());

        // 更新粉丝访问时间
        String fromUserName = jsonObj.getString("FromUserName");
        int createTime = jsonObj.getIntValue("CreateTime");
        if(!StringUtils.isEmpty(fromUserName) && createTime > 0) {
            MpUserVisit mpUserVisit = new MpUserVisit();
            mpUserVisit.setAppid(appid);
            mpUserVisit.setFromUserName(fromUserName);
            mpUserVisit.setCreateTime(createTime);
            try {
                amqpTemplate.convertAndSend(QueueConstants.QUEUE_MPWEIXIN_USER_VISIT, mpUserVisit);
            } catch (Exception e) {
                log.error("mpweixin user visit error:{}", e);
            }
        } else {
            log.error("xiaoc>> 获取粉丝访问时间失败，jsonObj: {}", jsonObj.toString());
        }

        // 根据消息类型分配处理任务
        String MsgType = jsonObj.getString("MsgType"); // 公众号的回调消息类型

        if("event".equalsIgnoreCase(MsgType)) { // 公众号事件类型
            // 暂时不要消息排重
			MPReceiveEventInfo info = JsonUtils.str2Bean(jsonObj.toString(), MPReceiveEventInfo.class);
            try {
                amqpTemplate.convertAndSend(QueueConstants.QUEUE_MPWEIXIN_EVENT_INFO, info);
            } catch (Exception e) {
                log.error("mpweixin event info error:{}", e);
            }
        }
        else if(StringUtils.inString(MsgType, MESSAGE_MPTYPE)) { // 公众号消息类型
            // 暂时不要消息排重

//			MPReceiveMsgInfo info = UtilJson.str2Bean(jsonObj.toString(), MPReceiveMsgInfo.class);
//			UtilRedis.lpush(RedisConstant.GOKU_MP_RECEIVE_MESSAGE, jsonObj.toString());
        }
        else {
//			_log.info("xiaoc>> 不支持的处理消息类型，MsgType: {}", MsgType);
        }

        return "success";
    }

    /**
     * 公众号套件回调消息解密
     * @param appid
     * @param msgSignature
     * @param timestamp
     * @param nonce
     * @param body
     * @return
     * @throws Exception
     */
    private JSONObject mpsuiteDecryp(String appid, String msgSignature, String timestamp, String nonce, String body) throws Exception {
        // 获取套件的相关信息
        String mpsuite_token = mpopenProperties.getToken();
        String mpsuite_encodingAESKey = mpopenProperties.getEncodingAESKey();

        if(StringUtils.isEmpty(appid) || StringUtils.isEmpty(mpsuite_token) || StringUtils.isEmpty(mpsuite_encodingAESKey)) {
            log.error("xiaoc>> 第三方平台套件配置信息有误，appid: {}, mpsuite_token: {}, mpsuite_encodingAESKey: {}", appid, mpsuite_token, mpsuite_encodingAESKey);
            return null;
        }

        // 解密数据
        WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(mpsuite_token, mpsuite_encodingAESKey, appid);
        String msg = null;
        try {
            msg = wxcpt.decryptMsg(msgSignature, timestamp, nonce, body);
        } catch(Exception e) {
            e.printStackTrace();
        }
        if(msg == null) {
            log.error("xiaoc>> 第三方平台套件消息回调数据解密失败， mpsuite_token: {}, appid: {}, mpsuite_encodingAESKey: {}", mpsuite_token, appid, mpsuite_encodingAESKey);
            log.error("xiaoc>> 第三方平台套件消息回调数据解密失败， msgSignature: {}, timestamp: {}, nonce: {}, body: {}", msgSignature, timestamp, nonce, body);
            return null;
        }

        // 消息转换成json
        JSONObject jsonObj = JsonUtils.xml2Json(msg);
        if(jsonObj == null) {
            log.error("第三方平台套件回调消息转json失败， msg: {}", msg);
            return null;
        }

        JSONObject jsonObjXml = jsonObj.getJSONObject("xml");
        if(jsonObjXml != null) {
            return jsonObjXml;
        }

        return jsonObj;
    }

}
